package com.tydic.borderer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tydic.borderer.domain.BordererInfo;
import com.tydic.borderer.domain.bo.BordererDetailBo;
import com.tydic.borderer.domain.request.*;
import com.tydic.borderer.domain.response.AccountInfo;
import com.tydic.borderer.domain.response.UserInfo;
import com.tydic.borderer.domain.vo.BordererInfoVo;
import com.tydic.borderer.mapper.BordererInfoMapper;
import com.tydic.borderer.service.IBordererInfoService;
import com.tydic.common.core.domain.model.LoginUser;
import com.tydic.common.core.enums.AuditStatusEnum;
import com.tydic.common.core.enums.MessageCategoryEnum;
import com.tydic.common.core.enums.ResponseCodeEnum;
import com.tydic.common.core.enums.UserTypeEnum;
import com.tydic.common.core.exception.api.ApiException;
import com.tydic.common.core.utils.ServletUtils;
import com.tydic.common.redis.constant.RedisKey;
import com.tydic.common.redis.utils.RedisUtils;
import com.tydic.common.satoken.utils.LoginHelper;
import com.tydic.system.domain.SysUser;
import com.tydic.system.mapper.SysUserMapper;
import com.tydic.system.mapper.SysUserRoleMapper;
import com.tydic.system.service.ISysMessageService;
import com.tydic.system.service.ISysUserService;
import com.tydic.system.utils.PasswordUtils;
import com.tydic.system.utils.SmsUtils;
import com.tydic.workflow.service.IBordererRegisterService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.util.List;
import java.util.Objects;

@Service
@RequiredArgsConstructor
@Slf4j
public class BordererInfoServiceImpl implements IBordererInfoService {
    private final BordererInfoMapper bordererInfoMapper;

    private final IBordererRegisterService bordererRegisterService;

    private final ISysMessageService messageService;

    private final SysUserMapper sysUserMapper;

    private final ISysUserService sysUserService;

    private final SysUserRoleMapper sysUserRoleMapper;


    @Override
    public BordererInfoVo queryById(String id) {
        return bordererInfoMapper.selectVoById(id);
    }

    @Override
    public BordererInfoVo selectByUserCode(String userCode) {
        return bordererInfoMapper.selectVoOne(Wrappers.lambdaQuery(BordererInfo.class).eq(BordererInfo::getUserCode, userCode));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(BordererInfo info) {
        if (StrUtil.isBlank(info.getProcInstId())) {
            ProcessInstance processInstance = bordererRegisterService.startProcess(info.getId());
            info.setProcInstId(processInstance.getProcessInstanceId());
            info.setAuditStatus(AuditStatusEnum.READY.getStatus());

            messageService.insertNeedHandler(MessageCategoryEnum.BORDER, info.getId(), "边民信息待审核", "边民:" + info.getName());
        }
        bordererInfoMapper.insertOrUpdate(info);
    }

    @Override
    public Page<BordererInfo> getBordererDetailsList(BordererDetailBo request) {
        return bordererInfoMapper.selectPage(request.build(), buildLambdaQueryWrapper(BeanUtil.toBean(request, BordererInfo.class)));
    }

    private LambdaQueryWrapper<BordererInfo> buildLambdaQueryWrapper(BordererInfo bordererInfo) {
        LambdaQueryWrapper<BordererInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(CharSequenceUtil.isNotBlank(bordererInfo.getPhoneNumber()), BordererInfo::getPhoneNumber, bordererInfo.getPhoneNumber());
        lqw.eq(CharSequenceUtil.isNotBlank(bordererInfo.getBordererCardNumber()), BordererInfo::getBordererCardNumber, bordererInfo.getBordererCardNumber());
        lqw.eq(CharSequenceUtil.isNotBlank(bordererInfo.getIdCardNumber()), BordererInfo::getIdCardNumber, bordererInfo.getIdCardNumber());
        lqw.eq(CharSequenceUtil.isNotBlank(bordererInfo.getUserCertificationStatus()), BordererInfo::getUserCertificationStatus, bordererInfo.getUserCertificationStatus());
        lqw.eq(CharSequenceUtil.isNotBlank(bordererInfo.getAuditStatus()), BordererInfo::getAuditStatus, bordererInfo.getAuditStatus());
        lqw.orderByDesc(BordererInfo::getCreateDate);
        return lqw;
    }

    @Override
    public Page<BordererInfo> pageByIds(int pageNo, int pageSize, List<String> ids) {
        LambdaQueryWrapper<BordererInfo> lqw = Wrappers.lambdaQuery(BordererInfo.class);
        lqw.in(CollUtil.isNotEmpty(ids), BordererInfo::getId, ids);
        return bordererInfoMapper.selectPage(new Page<>(pageNo, pageSize), lqw);
    }

    @Override
    public BordererInfo getBordererInfoByUserCode(String userCode) {
        return bordererInfoMapper.selectByUserCode(userCode);
    }

    @Override
    public BordererInfo getBordererInfoByPhoneNumber(String phoneNumber) {
        return bordererInfoMapper.selectByPhoneNumber(phoneNumber);
    }

    @Override
    public BordererInfo getBordererInfoById(String id) {
        return bordererInfoMapper.selectById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BordererInfo update(BordererInfo info) {
        bordererInfoMapper.updateById(info);
        return bordererInfoMapper.selectById(info.getId());
    }

    @Override
    public BordererInfo selectByBordererCardNumber(String bordererGroup, String bordererCardNumber) {
        return bordererInfoMapper.selectByBorderGroupAndBordererCardNumber(bordererGroup, bordererCardNumber);
    }


    @Override
    public BordererInfo queryBorderInfo(String bordererCardNumber) {
        LoginUser currentUser = LoginHelper.getLoginUser();
        BordererInfo bordererInfo = getBordererInfoByUserCode(currentUser.getUserCode());
        if (bordererInfo == null) {
            throw new ApiException("您当前不是边民角色");
        }
        if (StrUtil.isBlank(bordererInfo.getBordererGroup())) {
            throw new ApiException("您当前未进入互助组，请联系平台运营人员");
        }
        return bordererInfoMapper.selectByBorderGroupAndBordererCardNumber(bordererInfo.getBordererGroup(), bordererCardNumber);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void approveBordererInfo(String id, String comment, boolean pass) {
        BordererInfo info = getBordererInfoById(id);

        if (Objects.isNull(info)) {
            throw new ApiException(ResponseCodeEnum.RECORD_NOT_EXIST.getMsg());
        }

        // 判断是否已经审核了
        if (!info.getAuditStatus().equals(AuditStatusEnum.READY.getStatus())) {
            throw new ApiException(ResponseCodeEnum.RECORD_NOT_EXIST.getMsg());
        }
        info.setAuditStatus(pass ? AuditStatusEnum.SUCCESS.getStatus() : AuditStatusEnum.FAIL.getStatus());
        bordererInfoMapper.insertOrUpdate(info);
        bordererRegisterService.submit(info.getProcInstId(), comment, pass);
        messageService.handleMessage(MessageCategoryEnum.BORDER, id);
        if (!pass) {
            messageService.insertMessageHandler(MessageCategoryEnum.BORDER, id, "边民信息待修改", "边民:" + info.getName(), info.getUserCode());
        }
    }

    @Override
    public int getNeedHandler() {
        LoginUser currentUser = LoginHelper.getLoginUser();
        if (UserTypeEnum.PLATFORM.equalsType(currentUser.getUserType())) {
            return bordererInfoMapper.selectNeedHandler(currentUser.getUserCode()).size();
        } else {
            return bordererInfoMapper.selectAllNeedHandler().size();
        }
    }

    @Override
    public BordererInfo getInfo(String id) {
        return bordererInfoMapper.selectById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void resetPassword(ResetPwdRequest request) {
        SysUser user = sysUserService.getUserByLoginCode(request.getPhone());
        if (user == null) {
            throw new ApiException("账号不存在!");
        }
        if (!CharSequenceUtil.equals(request.getPwd(), request.getConfirmPwd())) {
            throw new ApiException("两次输入的密码不一致!");
        }
        SmsUtils.checkSmsCode(request.getPhone(), request.getValidateCode());
        checkPhotoCode(request.getPhotoCode());
        user.setUserCode(user.getUserCode());
        user.setPassword(PasswordUtils.encryptPassword(request.getPwd()));
        sysUserMapper.updateById(user);
    }

    private void checkPhotoCode(String imageCode) {
        String redisKey = RedisKey.IMAGE_CODE.createRedisKey(imageCode);

        String redisCode = RedisUtils.getCacheObject(redisKey);
        if (CharSequenceUtil.isEmpty(redisCode)) {
            throw new ApiException("验证码错误!");
        } else {
            if (!redisCode.equalsIgnoreCase(imageCode)) {
                throw new ApiException("验证码错误!");
            }
        }
        RedisUtils.deleteObject(redisKey);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void registerValidatePhone(BordererValidatePhoneRequest request) {
        SmsUtils.checkSmsCode(request.getPhone(), request.getValidateCode());
        checkPhotoCode(request.getPhotoCode());
        SysUser result = sysUserService.getUserByLoginCode(request.getPhone());
        if (result == null) {
            String sessionId = ServletUtils.getRequest().getSession().getId();
            String phoneRedisKey = RedisKey.ACCOUNT_REGISTER_INFO.createRedisKey(sessionId);
            RedisUtils.setCacheObject(phoneRedisKey, request.getPhone(), Duration.ofHours(24));
        } else {
            throw new ApiException("当前手机号码已经注册!");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void registerInputPwd(InputPwdRequest request) {
        if (!CharSequenceUtil.equals(request.getPwd(), request.getConfirmPwd())) {
            throw new ApiException("两次输入的密码不一致!");
        }
        String sessionId = ServletUtils.getRequest().getSession().getId();
        String phoneRedisKey = RedisKey.ACCOUNT_REGISTER_INFO.createRedisKey(sessionId);
        String redisPhone = RedisUtils.getCacheObject(phoneRedisKey);
        if (CharSequenceUtil.isBlank(redisPhone)) {
            throw new ApiException("手机号码不能为空!");
        }

        SysUser user = sysUserService.getUserByLoginCode(redisPhone);
        if (ObjectUtil.isNotNull(user)) {
            throw new ApiException("当前手机号码已经注册!");
        }
        user = new SysUser();
        user.setUserName(String.valueOf(System.currentTimeMillis()));
        user.setPassword(PasswordUtils.encryptPassword(request.getPwd()));
        user.setUserType(UserTypeEnum.BORDERER.getUserType());
        user.setMgrType("0");
        user.setStatus("0");
        user.setMobile(redisPhone);
        user.setPhone(redisPhone);
        sysUserMapper.insertOrUpdate(user);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void registerPersonInfo(PersonInfoRequest request) {
        SysUser user = getLoginUser();
        BordererInfo appBordererInfo = getBordererInfoByUserCode(user.getUserCode());
        if (ObjectUtil.isNull(appBordererInfo)) {

            appBordererInfo = new BordererInfo();
            appBordererInfo.setUserCode(user.getUserCode());
            appBordererInfo.setPhoneNumber(user.getMobile());
            BeanUtil.copyProperties(request, appBordererInfo, CopyOptions.create().ignoreNullValue().setIgnoreError(true));
            bordererInfoMapper.insertOrUpdate(appBordererInfo);
        } else if (CharSequenceUtil.equals(appBordererInfo.getAuditStatus(), AuditStatusEnum.FAIL.getStatus())) {
            appBordererInfo.setAuditStatus(AuditStatusEnum.READY.getStatus());
            BeanUtil.copyProperties(request, appBordererInfo, CopyOptions.create().ignoreNullValue().setIgnoreError(true));
            bordererInfoMapper.insertOrUpdate(appBordererInfo);
        } else {
            throw new ApiException("不可以重复实名登记!");
        }
    }

    private SysUser getLoginUser() {
        LoginUser currentUser = LoginHelper.getLoginUser();
        return sysUserMapper.selectById(currentUser.getUserCode());
    }

    @Override
    public AccountInfo getAccountInfo() {
        SysUser user = getLoginUser();
        AccountInfo accountInfo = new AccountInfo();
        BeanUtil.copyProperties(user, accountInfo);
        return accountInfo;
    }

    @Override
    public UserInfo getUserInfo() {
        LoginUser currentUser = LoginHelper.getLoginUser();
        BordererInfo info = getBordererInfoByUserCode(currentUser.getUserCode());
        UserInfo userInfo = new UserInfo();
        BeanUtil.copyProperties(info, userInfo);
        return userInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserInfo(UserInfo request) {
        LoginUser currentUser = LoginHelper.getLoginUser();
        BordererInfo info = getBordererInfoByUserCode(currentUser.getUserCode());
        BeanUtil.copyProperties(request, info, CopyOptions.create().ignoreNullValue().ignoreError());
        bordererInfoMapper.updateById(info);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePhoneNumber(ValidatePhoneRequest request) {
        SmsUtils.checkSmsCode(request.getPhoneNumber(), request.getSmsCode());
        SysUser user = sysUserService.getUserByLoginCode(request.getPhoneNumber());
        if (ObjectUtil.isNotNull(user)) {
            throw new ApiException("当前手机号码已经注册!");
        }
        SysUser select = getLoginUser();
        select.setLoginCode(request.getPhoneNumber());
        select.setMobile(request.getPhoneNumber());
        select.setPhone(request.getPhoneNumber());
        sysUserMapper.updateById(select);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void validatePhone(ValidatePhoneRequest request) {
        SmsUtils.checkSmsCode(request.getPhoneNumber(), request.getSmsCode());
        SysUser user = getLoginUser();
        if (!CharSequenceUtil.equals(user.getLoginCode(), request.getPhoneNumber())) {
            throw new ApiException("手机号码和当前账号不匹配!");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePwd(UpdatePwdRequest request) {
        if (!CharSequenceUtil.equals(request.getNewPwd(), request.getConfirmPwd())) {
            throw new ApiException("两次输入的密码不一致!");
        }
        SysUser user = getLoginUser();
        if (!PasswordUtils.match(request.getOlderPwd(), user.getPassword())) {
            throw new ApiException("旧密码错误!");
        }
        String newPwd = PasswordUtils.encryptPassword(request.getNewPwd());
        user.setPassword(newPwd);
        sysUserMapper.updateById(user);
    }

    @Override
    public BordererInfo findByIdCardNumber(String idCardNumber) {
        return bordererInfoMapper.selectOne(Wrappers.lambdaQuery(BordererInfo.class).eq(BordererInfo::getIdCardNumber, idCardNumber), false);
    }

    @Override
    public List<BordererInfo> findByIds(List<String> ids) {
        return bordererInfoMapper.selectBatchIds(ids);
    }

}
